#if _DEBUG

#include <cppunit/config/SourcePrefix.h>

#include "../source/Modifies.h"
#include "TestModifies.h"
#include <iterator>
#define MAX 32
using namespace std;
void ModifiesTest::SetUp(void)
{
}


void ModifiesTest::TearDown(void)
{
}

CPPUNIT_TEST_SUITE_REGISTRATION(ModifiesTest);

/*void ModifiesTest::TestConstructor() {
	PKB *p = new PKB;
	mod1.InitializeModifies(MAX);
	int i = mod1.num_of_statements;
	CPPUNIT_ASSERT(i == MAX);
}*/
/*
void ModifiesTest::TestInsertModifies() {
	STMT s;
	s.statement_number = 1;
	mod1.InsertModifies(s, 2, 3);
	CPPUNIT_ASSERT(mod1.modifies_list.size() == 1);

}

void ModifiesTest::TestInsertDupModifies(){
	STMT s;
	s.statement_number = 1;
	mod1.InsertModifies(s, 2, 3);
	CPPUNIT_ASSERT(mod1.modifies_list.size() == 1);
}


void ModifiesTest::TestInsertSecond() {
	STMT s;
	s.statement_number = 1;
	mod1.InsertModifies(s, 2, 4);
	CPPUNIT_ASSERT(mod1.modifies_list.size() == 2);
}

void ModifiesTest::TestClearMap() {
	mod1.modifies_list.clear();
	CPPUNIT_ASSERT(mod1.modifies_list.size() == 0);
}*/


// Emulates Modifies state after evaluating sample code in Assign4
void ModifiesTest::TestInsertActualRelations() {

	// symbol table:
	// x = 0, y = 1, z = 2, i = 3

	// proc table:
	// 'Main' = 0, 'P' = 1

	STMT s1, s2, s3, s4, s5;
	s1.node_type = ASSIGN;
	s1.statement_number = 1;
	s2.node_type = WHILE;
	s2.statement_number = 2;
	s3.node_type = ASSIGN;
	s3.statement_number = 3;
	s4.node_type = CALL;
	s4.statement_number = 4;
	s5.node_type = ASSIGN;
	s5.statement_number = 5;
	
	// x = x + y + z
	mod1.InsertModifies(s1, 0, 0);
	//mod1.InsertModifies(s1, 1, 0);
	//mod1.InsertModifies(s1, 2, 0);

	// while i { y = x + i*2; Call P; } }
	mod1.InsertModifies(s2, 1, 0);
	mod1.InsertModifies(s2, 0, 0);
	
	// y = x + i*2
	mod1.InsertModifies(s3, 1, 0);
//	mod1.InsertModifies(s3, 2, 0);

	// call P;
	mod1.InsertModifies(s4, 0, 0);

	// x = x + z;
	mod1.InsertModifies(s5, 0, 1);

	STMT rigid;
	int var_i = 10;
	for(int k = 20; k <MAX; k++ ) {

		rigid.node_type = ASSIGN;
		rigid.statement_number = var_i;
		mod1.InsertModifies(rigid, var_i, 0);
		var_i++;

	}

	//CPPUNIT_ASSERT(mod1.modifies_list.size() > 3);
	

}

void ModifiesTest::TestAssignmentModifiesVariable() {
	// check what statements modify x (1, 2, 4, 5)
	STMT_ARRAY s_a1 = mod1.GetAssignmentModifiesVariable(0);
	CPPUNIT_ASSERT(s_a1.size() == 4);
	STMT s;
	s.node_type = ASSIGN;
	s.statement_number = 1;
	set<STMT>::iterator s_i1 = s_a1.find(s);
	CPPUNIT_ASSERT(s_i1 != s_a1.end());
	s.statement_number = 2;
	s_i1 = s_a1.find(s);
	CPPUNIT_ASSERT(s_i1 != s_a1.end());
	s.statement_number = 4;
	s_i1 = s_a1.find(s);
	CPPUNIT_ASSERT(s_i1 != s_a1.end());
	s.statement_number = 5;
	s_i1 = s_a1.find(s);
	CPPUNIT_ASSERT(s_i1 != s_a1.end());
}

void ModifiesTest::TestVariableModifiedByAssignment() {
	STMT s;

	// test statement 1 modifies x
	s.node_type = ASSIGN;
	s.statement_number = 1;
	VARINDEX v_a1 = mod1.GetVariableModifiedByAssignment(s);
	CPPUNIT_ASSERT(v_a1 == 0);



	// test statement 3 modifies y
	s.node_type = ASSIGN;
	s.statement_number = 3;
	VARINDEX v_a2 = mod1.GetVariableModifiedByAssignment(s);
	CPPUNIT_ASSERT(v_a2 == 1);

	// test statement 5 modifies y
	s.node_type = ASSIGN;
	s.statement_number = 5;
	VARINDEX v_a3 = mod1.GetVariableModifiedByAssignment(s);
	CPPUNIT_ASSERT(v_a3 == 0);

}

void ModifiesTest::TestGetAssignmentModifies() {
	STMT s;
	// test statement 1 modifies x
	s.node_type = ASSIGN;
	s.statement_number = 1;
	bool t = mod1.GetAssignmentModifies(s,0);
	CPPUNIT_ASSERT(t == true);
	
	// test statement 3 modifies y
	s.node_type = ASSIGN;
	s.statement_number = 3;
	t = mod1.GetAssignmentModifies(s, 1);
	CPPUNIT_ASSERT(t == true);

	// test statement 5 modifies y
	s.node_type = ASSIGN;
	s.statement_number = 5;
	t = mod1.GetAssignmentModifies(s, 0);
	CPPUNIT_ASSERT(t == true);

	// test statement 1 does not modify y
	s.node_type = ASSIGN;
	s.statement_number = 1;
	t = mod1.GetAssignmentModifies(s,1);
	CPPUNIT_ASSERT(t == false);

}


void ModifiesTest::TestContainerModifiesVariable() {
	// check what statements modify x (1, 2, 4, 5)
	STMT parent1;
	parent1.node_type=WHILE;
	parent1.statement_number = 2;

	STMT child1;
	child1.node_type = ASSIGN;
	child1.statement_number = 3;

	STMT child2;
	child2.node_type = ASSIGN;
	child2.statement_number = 4;


	mod1.parent_test.InsertParent(parent1, child1);
	mod1.parent_test.InsertParent(parent1, child2);
	mod1.proc_test.InsertProc("Main");
	mod1.proc_test.InsertProc("P");
	STMT_ARRAY s_a1 = mod1.GetContainerModifiesVariable(1, WHILE);

	// test that statement 2 (while) modifies y : true
	STMT s;
	s.node_type = WHILE;
	s.statement_number = 2;
	set<STMT>::iterator s_i1 = s_a1.find(s);
//	cout << "size is" << s_a1.size() << endl;
	CPPUNIT_ASSERT(s_i1 != s_a1.end());

	// test that statement 3 (assign) modifies y : false since not container
	s.statement_number = 3;
	s.node_type = ASSIGN;
	s_i1 = s_a1.find(s);
	CPPUNIT_ASSERT(s_i1 == s_a1.end());

}

void ModifiesTest::TestGetVariablesModifiedByContainer() {
	STMT parent1;
	parent1.node_type=WHILE;
	parent1.statement_number = 2;
	VARINDEX_ARRAY v_a1 = mod1.GetVariablesModifiedByContainer(parent1);

	VARINDEX_ARRAY::iterator v_i1 = v_a1.find(0);
	CPPUNIT_ASSERT(v_i1 != v_a1.end());

	v_i1 = v_a1.find(1);
	CPPUNIT_ASSERT(v_i1 != v_a1.end());

	v_i1 = v_a1.find(2);
	CPPUNIT_ASSERT(v_i1 == v_a1.end());
}


void ModifiesTest::TestGetProceduresModifiesVariable(){

	PROCINDEX_ARRAY p_a1 = mod1.GetProceduresModifiesVariable(1);

	// Test if Main modifies y: true
	PROCINDEX_ARRAY::iterator p_i1 = p_a1.find(0);
	CPPUNIT_ASSERT(p_i1 != p_a1.end());

	// Test if P modifies y: false
	p_i1 = p_a1.find(1);
	CPPUNIT_ASSERT(p_i1 == p_a1.end());

	p_a1 = mod1.GetProceduresModifiesVariable(0);
	// Test if Main modifies x: true

	PROCINDEX_ARRAY::iterator p_i2 = p_a1.find(0);
	CPPUNIT_ASSERT(p_i2 != p_a1.end());

	// Test if P modifies x: false
	p_i2 = p_a1.find(1);
	CPPUNIT_ASSERT(p_i2 != p_a1.end());


}


void ModifiesTest::TestGetVariablesModifiedByProcedure() {

	VARINDEX_ARRAY v_a1 = mod1.GetVariablesModifiedByProcedure(0);
	//CPPUNIT_ASSERT(v_a1.size() == 2);

	// Test if Main modifies x: true
	VARINDEX_ARRAY::iterator v_i1 = v_a1.find(0);
	CPPUNIT_ASSERT(v_i1 != v_a1.end());

	// Test if Main modifies y: true
	v_i1 = v_a1.find(1);
	CPPUNIT_ASSERT(v_i1 != v_a1.end());

	// Test if Main modifies z: false
	v_i1 = v_a1.find(2);
	CPPUNIT_ASSERT(v_i1 == v_a1.end());

}


void ModifiesTest::TestGetContainerModifies() 
{
	STMT ifstmt;
	ifstmt.node_type = WHILE;
	ifstmt.statement_number = 2;

	CPPUNIT_ASSERT(mod1.GetContainerModifies(ifstmt, 0, WHILE));
	CPPUNIT_ASSERT(mod1.GetContainerModifies(ifstmt, 1, WHILE));
	CPPUNIT_ASSERT(!mod1.GetContainerModifies(ifstmt, 2, WHILE));

}

void ModifiesTest::TestGetStatementModifies() 
{
	STMT s1, s2, s4, s5;
	s1.statement_number = 1;
	s2.statement_number = 2;
	s4.statement_number = 4;
	s5.statement_number = 5;

	// s1 modify x: true
	CPPUNIT_ASSERT(mod1.GetStatementModifies(s1, 0));
	// s1 modify y: false
	CPPUNIT_ASSERT(!mod1.GetStatementModifies(s1, 1));

	// s2 modify y
	CPPUNIT_ASSERT(mod1.GetStatementModifies(s2, 1));
	// s2 modify x
	CPPUNIT_ASSERT(mod1.GetStatementModifies(s2, 0));
	// s2 modify i:false
	CPPUNIT_ASSERT(!mod1.GetStatementModifies(s2, 3));
	// s2 modify z: false
	CPPUNIT_ASSERT(!mod1.GetStatementModifies(s2, 2));


	// s4 modify x
	CPPUNIT_ASSERT(mod1.GetStatementModifies(s4, 0));
	// s4 modify i:false
	CPPUNIT_ASSERT(!mod1.GetStatementModifies(s4, 3));
	// s4 modify z: false
	CPPUNIT_ASSERT(!mod1.GetStatementModifies(s4, 2));
	// s4 modify y: false
	CPPUNIT_ASSERT(!mod1.GetStatementModifies(s4, 1));

	// s5 modify x
	CPPUNIT_ASSERT(mod1.GetStatementModifies(s5, 0));
	// s5 modify i:false
	CPPUNIT_ASSERT(!mod1.GetStatementModifies(s5, 3));
	// s5 modify z: false
	CPPUNIT_ASSERT(!mod1.GetStatementModifies(s5, 2));
	// s5 modify y: false
	CPPUNIT_ASSERT(!mod1.GetStatementModifies(s5, 1));

}

void ModifiesTest::TestGetProcedureModifies()
{

	CPPUNIT_ASSERT(mod1.GetProcedureModifies(0, 0));

	CPPUNIT_ASSERT(mod1.GetProcedureModifies(0, 1));
	
	CPPUNIT_ASSERT(!mod1.GetProcedureModifies(0, 2));

	CPPUNIT_ASSERT(mod1.GetProcedureModifies(1, 0));
}


#endif